package com.boot.project.core.model.result;

import cn.hutool.core.util.StrUtil;
import com.boot.project.core.constant.SystemConstant;
import com.boot.project.core.model.system.entity.Resource;
import com.boot.project.core.model.system.entity.User;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.util.*;

/**
 * @description:
 * @author: tsing
 * @create: 2021-01-22 22:44
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ProfileResult implements Serializable {

    private Long id; // 用户id
    private String username; // 用户名
    private Long roleId; // 角色id
    private Boolean firstLogin; // 是否第一次登陆，是第一次登陆的话前端页面会强制修改密码

    private PermissionResult result; // 权限信息

    public ProfileResult(User user, Boolean firstLogin, List<Resource> list) {
        // 1.根据user赋值
        this.id = user.getId();
        this.username = user.getUsername();
        this.roleId = user.getRoleId();
        this.firstLogin = firstLogin;

        // 2.根据list处理出想要的数据
        List<Resource> menus = new ArrayList<>();
        Set<String> buttons = new LinkedHashSet<>();
        // 2.1.将list中的数据根据type的不同封装到不同的集合中去
        for (Resource resource : list) {
            if (SystemConstant.RESOURCE_TYPE_INDEX.equals(resource.getType())
                    || SystemConstant.RESOURCE_TYPE_MENU.equals(resource.getType())) {
                menus.add(resource);
            }
            if (StrUtil.isNotBlank(resource.getPermission())) {
                String[] pArray = resource.getPermission().split(",");
                Collections.addAll(buttons, pArray);
            }
        }
        // 2.2.将menus转成有父子关系的对象List
        List<Map<String, Object>> treeMenus = new ArrayList<>();
        if (!CollectionUtils.isEmpty(menus)) {
            treeMenus = transListToTreeList(menus);
        }
        this.result = new PermissionResult(treeMenus, buttons);
    }

    /**
     * 将menus转成有父子关系的对象List，关联属性为parentId。只适用于二级菜单
     * @param menus 需要转化的集合
     * @return
     */
    private List<Map<String, Object>> transListToTreeList(List<Resource> menus) {
        // 先根据parentId排序
        Collections.sort(menus, Comparator.comparingLong(o -> o.getParentId().longValue()));

        // 存放树形的处理结果的list
        List<Map<String, Object>> treeList = new ArrayList<>();
        // 这个map用于存放returnList中元素的id和其索引的对应关系，即key是menu的id值，值是这个menu在returnList中的索引
        Map<Long, Integer> indexMap = new HashMap<>();
        for (Resource resource: menus) {
            // 构建菜单数据
            Map<String, Object> subMap = this.buildMapFromResource(resource);
            // 根据是否为父菜单进行不同的操作
            if (resource.getParentId() == 0) {
                // 父菜单的情况
                treeList.add(subMap);
                indexMap.put(resource.getId(), treeList.size() - 1);
            } else {
                // 子菜单的情况
                List<Map<String, Object>> children = (List<Map<String, Object>>) treeList
                        .get(indexMap.get(resource.getParentId())).get("children");
                children.add(subMap);
            }
        }

        // 排序
        // 1.先排子菜单
        for (Map<String, Object> map : treeList) {
            if (map.get("children") != null) {
                Collections.sort((List<Map<String, Object>>) map.get("children"), (o1, o2) -> {
                    Integer sort1 = (Integer) o1.get("sort");
                    Integer sort2 = (Integer) o2.get("sort");
                    return sort1.compareTo(sort2);

                });
            }
        }

        // 2.再排父菜单
        Collections.sort(treeList, (o1, o2) -> {
            Integer sort1 = (Integer) o1.get("sort");
            Integer sort2 = (Integer) o2.get("sort");
            return sort1.compareTo(sort2);
        });
        return treeList;
    }

    /**
     * 根据resource对象构建菜单map的信息
     * @param resource 资源对象
     * @return
     */
    private Map<String, Object> buildMapFromResource(Resource resource) {
        Map<String, Object> subMap = new HashMap<>();
        subMap.put("id", resource.getId());
        subMap.put("icon", resource.getIcon());
        subMap.put("name", resource.getName());
        subMap.put("sort", resource.getSort());
        subMap.put("parentId", resource.getParentId());
        subMap.put("children", new ArrayList<Map<String, Object>>());

        String url = resource.getUrl();
        if (StrUtil.isNotBlank(url)) {
            if (url.startsWith("/")) {
                url = "#" + url.substring(1);
            } else {
                url = "#" + url;
            }
        }
        subMap.put("url", url);
        return subMap;
    }
}
